package com.ruoyi.fin.service.impl;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.fin.domain.FinAccount;
import com.ruoyi.fin.domain.FinTransaction;
import com.ruoyi.fin.mapper.FinAccountMapper;
import com.ruoyi.fin.mapper.FinTransactionMapper;
import com.ruoyi.fin.service.IFinReportService;
import com.ruoyi.fin.util.CustomExcelUtil;

/**
 * 财务报表服务实现
 * 
 * @author ruoyi
 */
@Service
public class FinReportServiceImpl implements IFinReportService {

    @Autowired
    private FinTransactionMapper finTransactionMapper;
    
    @Autowired
    private FinAccountMapper finAccountMapper;
    
    /**
     * 获取利润报表数据
     * 
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @param compareType 比较类型（同比:year, 环比:month）
     * @return 利润报表数据
     */
    @Override
    public List<Map<String, Object>> getProfitReportData(Date startDate, Date endDate, String compareType) {
        List<Map<String, Object>> result = new ArrayList<>();
        
        // 默认日期范围为当前月
        if (startDate == null || endDate == null) {
            Calendar cal = Calendar.getInstance();
            cal.set(Calendar.DAY_OF_MONTH, 1);
            startDate = cal.getTime();
            cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
            endDate = cal.getTime();
        }
        
        // 按月统计数据
        Map<String, Object> currentPeriodData = calculateProfitByMonth(startDate, endDate);
        result.add(currentPeriodData);
        
        // 计算比较数据（同比或环比）
        if ("year".equals(compareType)) {
            // 同比（去年同期）
            Calendar cal = Calendar.getInstance();
            cal.setTime(startDate);
            cal.add(Calendar.YEAR, -1);
            Date lastYearStart = cal.getTime();
            
            cal.setTime(endDate);
            cal.add(Calendar.YEAR, -1);
            Date lastYearEnd = cal.getTime();
            
            Map<String, Object> lastYearData = calculateProfitByMonth(lastYearStart, lastYearEnd);
            lastYearData.put("periodName", "去年同期");
            result.add(lastYearData);
        } else if ("month".equals(compareType)) {
            // 环比（上月）
            Calendar cal = Calendar.getInstance();
            cal.setTime(startDate);
            cal.add(Calendar.MONTH, -1);
            Date lastMonthStart = cal.getTime();
            
            cal.setTime(endDate);
            cal.add(Calendar.MONTH, -1);
            Date lastMonthEnd = cal.getTime();
            
            Map<String, Object> lastMonthData = calculateProfitByMonth(lastMonthStart, lastMonthEnd);
            lastMonthData.put("periodName", "上月同期");
            result.add(lastMonthData);
        }
        
        return result;
    }
    
    /**
     * 按月计算利润数据
     * 
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return 月度利润数据
     */
    private Map<String, Object> calculateProfitByMonth(Date startDate, Date endDate) {
        Map<String, Object> data = new HashMap<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        String periodName = sdf.format(startDate);
        data.put("periodName", periodName);
        
        // 查询指定时间范围内的收入交易
        Map<String, Object> incomeParams = new HashMap<>();
        incomeParams.put("startDate", startDate);
        incomeParams.put("endDate", endDate);
        incomeParams.put("type", 1L); // 收入类型
        BigDecimal totalIncome = finTransactionMapper.selectTotalAmountByDateRangeAndType(incomeParams);
        totalIncome = totalIncome == null ? new BigDecimal("0.00") : totalIncome;
        
        // 查询指定时间范围内的支出交易
        Map<String, Object> expenseParams = new HashMap<>();
        expenseParams.put("startDate", startDate);
        expenseParams.put("endDate", endDate);
        expenseParams.put("type", 2L); // 支出类型
        BigDecimal totalExpense = finTransactionMapper.selectTotalAmountByDateRangeAndType(expenseParams);
        totalExpense = totalExpense == null ? new BigDecimal("0.00") : totalExpense;
        
        // 计算净利润
        BigDecimal netProfit = totalIncome.subtract(totalExpense);
        
        data.put("totalIncome", totalIncome);
        data.put("totalExpense", totalExpense);
        data.put("netProfit", netProfit);
        
        return data;
    }
    
    /**
     * 获取所有账户当前余额数据
     * 
     * @return 账户余额数据列表
     */
    @Override
    public List<Map<String, Object>> getAccountBalanceData() {
        // 查询所有启用的账户
        FinAccount queryAccount = new FinAccount();
        queryAccount.setStatus(1L); // 启用状态
        List<FinAccount> accounts = finAccountMapper.selectFinAccountList(queryAccount);
        
        List<Map<String, Object>> result = new ArrayList<>();
        BigDecimal totalBalance = BigDecimal.ZERO;
        
        // 处理每个账户的数据
        for (FinAccount account : accounts) {
            Map<String, Object> accountData = new HashMap<>();
            accountData.put("accountId", account.getId());
            accountData.put("accountName", account.getName());
            accountData.put("accountNo", account.getAccountNo());
            accountData.put("bankName", account.getBankName());
            accountData.put("balance", account.getBalance());
            
            totalBalance = totalBalance.add(account.getBalance());
            result.add(accountData);
        }
        
        // 添加总计
        Map<String, Object> totalData = new HashMap<>();
        totalData.put("accountId", 0);
        totalData.put("accountName", "总资产");
        totalData.put("accountNo", "");
        totalData.put("bankName", "");
        totalData.put("balance", totalBalance);
        result.add(totalData);
        
        return result;
    }
    
    /**
     * 获取账户余额历史趋势数据
     * 
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @param accountId 账户ID（为空则查询所有账户）
     * @return 账户余额历史趋势数据
     */
    @Override
    public List<Map<String, Object>> getAccountBalanceTrendData(Date startDate, Date endDate, Long accountId) {
        // 默认日期范围为最近30天
        if (startDate == null || endDate == null) {
            endDate = DateUtils.getNowDate();
            Calendar cal = Calendar.getInstance();
            cal.setTime(endDate);
            cal.add(Calendar.DAY_OF_MONTH, -30);
            startDate = cal.getTime();
        }
        
        // 查询账户余额历史变动数据
        Map<String, Object> params = new HashMap<>();
        params.put("startDate", startDate);
        params.put("endDate", endDate);
        if (accountId != null) {
            params.put("accountId", accountId);
        }
        
        List<Map<String, Object>> rawData = finAccountMapper.selectAccountBalanceTrend(params);
        
        // 查询账户初始余额（截至开始日期前的余额）
        Map<String, BigDecimal> initialBalances = getInitialBalances(startDate, accountId);
        
        // 构建完整的日期序列，并计算每天的余额
        return calculateDailyBalances(rawData, initialBalances, startDate, endDate);
    }
    
    /**
     * 获取账户在指定日期前的初始余额
     */
    private Map<String, BigDecimal> getInitialBalances(Date beforeDate, Long specificAccountId) {
        Map<String, BigDecimal> initialBalances = new HashMap<>();
        
        // 查询所有启用的账户
        FinAccount queryAccount = new FinAccount();
        queryAccount.setStatus(1L);
        if (specificAccountId != null) {
            queryAccount.setId(specificAccountId);
        }
        
        List<FinAccount> accounts = finAccountMapper.selectFinAccountList(queryAccount);
        
        for (FinAccount account : accounts) {
            // 获取该账户在指定日期之前的所有交易
            FinTransaction queryTrans = new FinTransaction();
            queryTrans.setAccountId(account.getId());
            List<FinTransaction> allTransactions = finTransactionMapper.selectFinTransactionList(queryTrans);
            
            // 计算初始余额
            BigDecimal initialBalance = BigDecimal.ZERO;
            for (FinTransaction transaction : allTransactions) {
                if (transaction.getTransactionDate().before(beforeDate)) {
                    if (transaction.getType() == 1L) { // 收入
                        initialBalance = initialBalance.add(transaction.getAmount());
                    } else if (transaction.getType() == 2L) { // 支出
                        initialBalance = initialBalance.subtract(transaction.getAmount());
                    }
                }
            }
            
            initialBalances.put(account.getId().toString(), initialBalance);
        }
        
        return initialBalances;
    }
    
    /**
     * 计算每个账户每天的余额
     */
    private List<Map<String, Object>> calculateDailyBalances(List<Map<String, Object>> rawData, 
                                                          Map<String, BigDecimal> initialBalances,
                                                          Date startDate, Date endDate) {
        // 创建日期序列
        List<String> dateSequence = generateDateSequence(startDate, endDate);
        
        // 按账户ID分组
        Map<String, List<Map<String, Object>>> accountGroupedData = rawData.stream()
                .collect(Collectors.groupingBy(m -> m.get("account_id").toString()));
        
        List<Map<String, Object>> resultData = new ArrayList<>();
        
        // 处理每个账户的数据
        for (String accountId : accountGroupedData.keySet()) {
            List<Map<String, Object>> accountData = accountGroupedData.get(accountId);
            String accountName = (String) accountData.get(0).get("account_name");
            
            // 获取账户初始余额
            BigDecimal balance = initialBalances.getOrDefault(accountId, BigDecimal.ZERO);
            
            // 创建该账户的日期-余额映射
            Map<String, BigDecimal> dateDailyChanges = accountData.stream()
                    .collect(Collectors.toMap(
                        m -> (String) m.get("record_date"),
                        m -> new BigDecimal(m.get("daily_change").toString()),
                        (v1, v2) -> v1.add(v2)));
            
            // 计算每天的余额并构建结果
            for (String date : dateSequence) {
                BigDecimal dailyChange = dateDailyChanges.getOrDefault(date, BigDecimal.ZERO);
                balance = balance.add(dailyChange);
                
                Map<String, Object> dailyData = new HashMap<>();
                dailyData.put("accountId", accountId);
                dailyData.put("accountName", accountName);
                dailyData.put("recordDate", date);
                dailyData.put("balance", balance);
                
                resultData.add(dailyData);
            }
        }
        
        return resultData;
    }
    
    /**
     * 生成指定日期范围内的日期序列
     */
    private List<String> generateDateSequence(Date startDate, Date endDate) {
        List<String> dateSequence = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        
        Calendar cal = Calendar.getInstance();
        cal.setTime(startDate);
        
        while (!cal.getTime().after(endDate)) {
            dateSequence.add(sdf.format(cal.getTime()));
            cal.add(Calendar.DAY_OF_MONTH, 1);
        }
        
        return dateSequence;
    }
    
    /**
     * 导出账户余额数据
     * 
     * @param params 查询参数
     * @return 导出的文件名
     */
    @Override
    public String exportAccountBalanceData(Map<String, Object> params) {
        List<Map<String, Object>> data = getAccountBalanceData();
        
        // 构建导出数据
        List<AccountBalanceExport> exportList = new ArrayList<>();
        for (Map<String, Object> item : data) {
            // 排除总计行
            if (Convert.toInt(item.get("accountId"), -1) != 0) {
                AccountBalanceExport export = new AccountBalanceExport();
                export.setAccountName(Convert.toStr(item.get("accountName"), ""));
                export.setAccountNo(Convert.toStr(item.get("accountNo"), ""));
                export.setBankName(Convert.toStr(item.get("bankName"), ""));
                export.setBalance(Convert.toBigDecimal(item.get("balance")));
                exportList.add(export);
            }
        }
        
        // 添加总计行
        BigDecimal totalBalance = BigDecimal.ZERO;
        for (AccountBalanceExport item : exportList) {
            totalBalance = totalBalance.add(item.getBalance());
        }
        AccountBalanceExport totalRow = new AccountBalanceExport();
        totalRow.setAccountName("总资产");
        totalRow.setBalance(totalBalance);
        exportList.add(totalRow);
        
        // 生成文件名
        String fileName = "账户余额统计_" + DateUtils.dateTimeNow() + ".xlsx";
        
        // 导出Excel
        CustomExcelUtil<AccountBalanceExport> util = new CustomExcelUtil<>(AccountBalanceExport.class);
        return util.exportExcelToFile(exportList, "账户余额统计", fileName);
    }
    
    /**
     * 账户余额导出对象
     */
    public static class AccountBalanceExport {
        /** 账户名称 */
        @Excel(name = "账户名称")
        private String accountName;
        
        /** 账号 */
        @Excel(name = "账号")
        private String accountNo;
        
        /** 银行名称 */
        @Excel(name = "银行名称")
        private String bankName;
        
        /** 当前余额 */
        @Excel(name = "当前余额(元)")
        private BigDecimal balance;
        
        public String getAccountName() {
            return accountName;
        }
        
        public void setAccountName(String accountName) {
            this.accountName = accountName;
        }
        
        public String getAccountNo() {
            return accountNo;
        }
        
        public void setAccountNo(String accountNo) {
            this.accountNo = accountNo;
        }
        
        public String getBankName() {
            return bankName;
        }
        
        public void setBankName(String bankName) {
            this.bankName = bankName;
        }
        
        public BigDecimal getBalance() {
            return balance;
        }
        
        public void setBalance(BigDecimal balance) {
            this.balance = balance;
        }
    }
    
    /**
     * 导出财务利润报表数据
     * 
     * @param params 查询参数
     * @return 导出的文件名
     */
    @Override
    public String exportProfitReportData(Map<String, Object> params) {
        // 解析日期
        Date startDate = null;
        Date endDate = null;
        String compareType = "month"; // 默认环比
        
        String startDateStr = (String) params.get("startDate");
        String endDateStr = (String) params.get("endDate");
        String compareTypeParam = (String) params.get("compareType");
        
        if (startDateStr != null && !startDateStr.isEmpty()) {
            startDate = DateUtils.parseDate(startDateStr);
        }
        
        if (endDateStr != null && !endDateStr.isEmpty()) {
            endDate = DateUtils.parseDate(endDateStr);
        }
        
        if (compareTypeParam != null && !compareTypeParam.isEmpty()) {
            compareType = compareTypeParam;
        }
        
        // 获取财务利润报表数据
        List<Map<String, Object>> data = getProfitReportData(startDate, endDate, compareType);
        
        // 构建导出数据
        List<ProfitReportExport> exportList = new ArrayList<>();
        for (Map<String, Object> item : data) {
            ProfitReportExport export = new ProfitReportExport();
            export.setPeriodName(Convert.toStr(item.get("periodName"), ""));
            export.setTotalIncome(Convert.toBigDecimal(item.get("totalIncome")));
            export.setTotalExpense(Convert.toBigDecimal(item.get("totalExpense")));
            export.setNetProfit(Convert.toBigDecimal(item.get("netProfit")));
            exportList.add(export);
        }
        
        // 生成文件名
        String fileName = "财务利润报表_" + DateUtils.dateTimeNow() + ".xlsx";
        
        // 导出Excel
        CustomExcelUtil<ProfitReportExport> util = new CustomExcelUtil<>(ProfitReportExport.class);
        return util.exportExcelToFile(exportList, "财务利润报表", fileName);
    }
    
    /**
     * 财务利润报表导出对象
     */
    public static class ProfitReportExport {
        /** 期间名称 */
        @Excel(name = "期间")
        private String periodName;
        
        /** 总收入 */
        @Excel(name = "收入(元)")
        private BigDecimal totalIncome;
        
        /** 总支出 */
        @Excel(name = "支出(元)")
        private BigDecimal totalExpense;
        
        /** 净利润 */
        @Excel(name = "利润(元)")
        private BigDecimal netProfit;
        
        public String getPeriodName() {
            return periodName;
        }
        
        public void setPeriodName(String periodName) {
            this.periodName = periodName;
        }
        
        public BigDecimal getTotalIncome() {
            return totalIncome;
        }
        
        public void setTotalIncome(BigDecimal totalIncome) {
            this.totalIncome = totalIncome;
        }
        
        public BigDecimal getTotalExpense() {
            return totalExpense;
        }
        
        public void setTotalExpense(BigDecimal totalExpense) {
            this.totalExpense = totalExpense;
        }
        
        public BigDecimal getNetProfit() {
            return netProfit;
        }
        
        public void setNetProfit(BigDecimal netProfit) {
            this.netProfit = netProfit;
        }
    }
} 